<?php

declare (strict_types=1);

namespace think\admin\service;

use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use think\admin\model\SysEmail;
use think\admin\Service;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

/**
 * 邮件服务
 * Class LocalEmailService
 * @package think\admin\service
 */
class LocalEmailService extends Service
{
    /**
     * emailHost
     * @var string
     */
    protected string $emailHost;

    /**
     * emailUsername
     * @var string
     */
    protected string $emailUsername;

    /**
     * emailPassword
     * @var string
     */
    protected string $emailPassword;

    /**
     * emailPort
     * @var string
     */
    protected string $emailPort;

    /**
     * emailFrom
     * @var string
     */
    protected string $emailFrom;

    /**
     * emailFromName
     * @var string
     */
    protected string $emailFromName;

    /**
     * 验证邮件验证码
     * @param string $code 验证码
     * @param string $email 邮箱验证
     * @return boolean
     */
    public function checkVerifyCode(string $code, string $email): bool
    {
        $cache = $this->app->cache->get(md5("code-{$email}"), []);
        return is_array($cache) && isset($cache['code']) && $cache['code'] == $code;
    }

    /**
     * 发送邮箱验证码
     * @param string $email 邮箱验证码
     * @param integer $wait 等待时间
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function sendVerifyCode(string $email, int $wait = 60): array
    {
        $content = '您的验证码为{code}，请在十分钟内完成操作！';
        $cache = $this->app->cache->get($ckey = md5("code-{$email}"), []);
        // 检查是否已经发送
        if (is_array($cache) && isset($cache['time']) && $cache['time'] > time() - $wait) {
            $dtime = ($cache['time'] + $wait < time()) ? 0 : ($wait - time() + $cache['time']);
            return [1, '邮箱验证码已经发送！', ['time' => $dtime]];
        }
        // 生成新的验证码
        [$code, $time] = [rand(1000, 9999), time()];
        $this->app->cache->set($ckey, ['code' => $code, 'time' => $time], 600);
        // 尝试发送邮件内容
        [$state] = $this->sendEmail($email, '您的邮件验证码', preg_replace_callback("|{(.*?)}|", function ($matches) use ($code) {
            return $matches[1] === 'code' ? $code : $matches[1];
        }, $content), '', (string)$code);
        if ($state) return [1, '邮件验证码发送成功！', [
            'time' => ($time + $wait < time()) ? 0 : ($wait - time() + $time)],
        ]; else {
            $this->app->cache->delete($ckey);
            return [0, '邮件发送失败，请稍候再试！', []];
        }
    }

    /**
     * 邮件发送
     * @param $to
     * @param string $subject
     * @param string $content
     * @param string $addAttachment
     * @param string $code
     * @return bool
     */
    public function sendEmail($to, string $subject = '', string $content = '', string $code = '', string $addAttachment = ''): bool
    {
        $mail = new PHPMailer(true);

        try {
            //Server settings
            //$mail->SMTPDebug = SMTP::DEBUG_SERVER;                    //启用详细调试输出
            $mail->isSMTP();                                            //使用 SMTP 发送
            $mail->CharSet = 'UTF-8';
            $mail->Host = $this->emailHost;                       //设置SMTP服务器通过
            $mail->SMTPAuth = true;                                   //启用SMTP认证
            $mail->Username = $this->emailUsername;                   //SMTP 用户名
            $mail->Password = $this->emailPassword;                   //SMTP 密码
            $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;            //启用隐式 TLS 加密
            $mail->Port = $this->emailPort;                       //要连接的TCP端口；如果您设置了 `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`，则使用 587

            //Recipients
            if (is_array($to)) {
                foreach ($to as $v) {
                    $mail->addAddress($v);
                }
            } else {
                $mail->addAddress($to);
            }

            $mail->setFrom($this->emailFrom, $this->emailFromName);

            //Attachments
            if (!empty($addAttachment)) {
                $mail->addAttachment($addAttachment);
            }

            //Content
            $mail->isHTML(true);                                  //Set email format to HTML
            $mail->Subject = $subject;
            $mail->Body = $content;


            if ($mail->send()) {
                $state = true;
                $message = '邮件发送成功！';
            } else {
                $state = false;
                $message = '邮件发送失败，请稍候再试！';
            }

            $dat = [
                'engine' => 'LOCAL',
                'send_account' => $this->emailFrom,
                'send_user' => $this->emailFromName,
                'receive_accounts' => implode(',', $to),
                'subject' => $subject,
                'content' => $content,
                'code' => $code,
                'receipt_info' => $message
            ];
            SysEmail::mk()->insert($dat);
            return $state;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * 发送邮件通知公告
     * @param array $email 邮箱
     * @param string $title 主题
     * @param string $content 内容
     * @param integer $wait 等待时间
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function sendNotice(array $email, string $title, string $content, int $wait = 60): array
    {
        // 尝试发送邮件内容
        [$state] = $this->sendEmail($email, $title, $content, '', '');
        if ($state) return [1, '邮件发送成功！', []]; else {
            return [0, '邮件发送失败，请稍候再试！', []];
        }
    }

    /**
     * 控制器初始化
     * @return void
     * @throws \think\admin\Exception
     */
    protected function initialize(): void
    {
        $config = sysconfig('EMAIL_LOCAL');
        $this->emailHost = $config['SQM_EMAIL_LOCAL_HOST'] ?? '';
        $this->emailUsername = $config['SQM_EMAIL_LOCAL_USERNAME'] ?? '';
        $this->emailPassword = $config['SQM_EMAIL_LOCAL_PASSWORD'] ?? '';
        $this->emailPort = $config['SQM_EMAIL_LOCAL_PORT'] ?? '';
        $this->emailFrom = $config['SQM_EMAIL_LOCAL_FROM'] ?? '';
        $this->emailFromName = $config['SQM_EMAIL_LOCAL_FROM_NICKNAME'] ?? '';
    }

}